package com.ruoyi.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.ruoyi.common.config.BigDataConfig;
import com.ruoyi.common.core.domain.FileObject;
import com.ruoyi.common.core.domain.IdName;
import com.ruoyi.common.core.domain.JSONObjectPro;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.enums.comlbs.*;
import com.ruoyi.common.exception.BigDataException;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.http.BigDataResponse;
import com.ruoyi.common.utils.http.HttpRequest;
import com.ruoyi.system.domain.AlarmType;
import com.ruoyi.system.domain.EquipmentManagement;
import com.ruoyi.system.domain.RealtimePositioning;
import com.ruoyi.system.domain.VehicleManagement;
import com.ruoyi.system.domain.request.realtimevideo.AlarmDataParam;
import com.ruoyi.system.domain.request.relatimepositioning.MapDeviceExportParam;
import com.ruoyi.system.domain.request.relatimepositioning.RegionDeviceParam;
import com.ruoyi.system.domain.request.reportstatistics.OriginalTrajectoryParam;
import com.ruoyi.system.domain.vo.common.DeviceGps;
import com.ruoyi.system.domain.vo.equipment.EquipmentInfo;
import com.ruoyi.system.domain.vo.realtimepositioning.MapDeviceExport;
import com.ruoyi.system.domain.vo.realtimevideo.AlarmData;
import com.ruoyi.system.service.*;
import com.ruoyi.system.utils.ComLbsUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 描述 实时定位Service业务层处理
 * 作者 ZhangPing
 * 创建时间 2023/8/16 16:59
 */
@Slf4j
@Service
public class IRealtimePositioningServiceImpl implements IRealtimePositioningService {

    @Autowired
    private IVehicleManagementService vehicleManagementService;
    @Autowired
    private IEquipmentManagementService equipmentManagementService;
    @Autowired
    private IDriverInfoService driverInfoService;
    @Autowired
    private ISysDeptService deptService;
    @Autowired
    private IAlarmTypeService alarmTypeService;
    @Autowired
    private CommonService commonService;
    @Autowired
    private BigDataConfig bigDataConfig;

    @Override
    public List<DeviceGps> originalTrajectory(OriginalTrajectoryParam param) {
        //远程调用接口
        BigDataResponse<JSONObject> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/gpsRelationData/queryGpsRelationPage", param.toJson(), JSONObject.class);
        JSONObject data = response.getData();
        if (!response.isSuccess() || ObjectUtils.isEmpty(data)) return Collections.emptyList();
        List<JSONObject> dataItems = data.getList("dataItems", JSONObject.class);
        if (ObjectUtils.isEmpty(dataItems)) return Collections.emptyList();
        //封装数据
        List<DeviceGps> resultList = dataItems.stream().map(ComLbsUtils::bigDataGpsFormat).collect(Collectors.toList());
//        Collections.reverse(resultList);
        return resultList;
    }

    /**
     * 获取定位信息
     */
    @Override
    public RealtimePositioning queryLastGps(String deviceId) {
        //查询单车定位信息
        BigDataResponse<JSONObject> response = HttpRequest.getBigData(bigDataConfig.getApiUrl() + "/gpsData/queryLastGpsOne", new JSONObjectPro().put("dvo", deviceId), JSONObject.class);
        if (!response.isSuccess() || response.getData() == null) return vehicleManagementService.getPositionByDeviceId(deviceId);
        //查询设备
        EquipmentManagement equipment = equipmentManagementService.getByDeviceId(deviceId);
        if (equipment == null) throw new ServiceException("绑定的设备未录入!");
        if (equipment.getEquipmentType() == null) equipment.setEquipmentType(EquipmentTypeEnum.VEHICLE.getCode());
        DeviceGps gps = ComLbsUtils.bigDataGpsFormat(response.getData());

        RealtimePositioning realtimePositioning = equipmentManagementService.getVehiclePositionByDeviceId(deviceId);
        String driver = driverInfoService.getNameGroupByEquipmentId(realtimePositioning.getEquipmentId());
        if (StringUtils.isNotBlank(driver)) {
            String[] drivers = driver.split(",");
            realtimePositioning.setDriverName(drivers.length > 0 ? drivers[0] : "");
        }

        //设置定位信息
        realtimePositioning.updateGpsData(gps);
        //设置基础信息
        RealtimePositioning detail = vehicleManagementService.getPositionByDeviceId(deviceId);
        realtimePositioning.updateBaseData(detail);
        //设置设备型号、设备类型、监管类型
        realtimePositioning.setEquipmentTypeStr(DictUtils.getDictLabel(DataDictTypeEnum.EQUIPMENT_TYPE.getText(), detail.getEquipmentType()));
        realtimePositioning.setDeviceModelStr(DictUtils.getDictLabel(DataDictTypeEnum.DEVICE_MODEL.getText(), detail.getDeviceModel()));
        realtimePositioning.setObjTypeName(DictUtils.getDictLabel(DataDictTypeEnum.OBJ_TYPE.getText(), detail.getObjType()));
        //设置公司名称
        List<SysDept> sysDepts = deptService.selectDeptList(new SysDept());
        Map<Long, SysDept> deptList = sysDepts.stream().collect(Collectors.toMap(SysDept::getDeptId, d -> d));
        SysDept parentDept = deptList.get(detail.getParentId());
        realtimePositioning.setParentId(detail.getParentId());
        if (parentDept != null) {
            realtimePositioning.setParentName(parentDept.getDeptName());
        }
        SysDept dept = deptList.get(detail.getCompanyId());
        if (dept != null) {
            realtimePositioning.setRemark(dept.getRemark());
        }
        //更新sts数据
        realtimePositioning.updateStsData(gps.getSts());
        //更新车辆状态
        realtimePositioning.setVehicleStatus(ComLbsUtils.getVehicleStatus(gps).getText());
        //更新卫星数量
        realtimePositioning.setSatelliteCount(gps.getSatelliteCount());


        String s;
        //卫星数量
        Map popMap = (HashMap) gps.getPop();
        s = PopMapEnum.SatelliteCount.getCode().toString();
        if (popMap.containsKey(s)) {
            realtimePositioning.setSatelliteCount(Integer.parseInt(popMap.get(s).toString()));
        } else {
            realtimePositioning.setSatelliteCount(0);
        }
        //信号强度
        s = PopMapEnum.SignalIntensity.getCode().toString();
        if (popMap.containsKey(s)) {
            realtimePositioning.setSignalIntensity(Integer.parseInt(popMap.get(s).toString()));
        } else {
            realtimePositioning.setSignalIntensity(0);
        }

        // 以下为北三字段
        //发送方id
        s = PopMapEnum.SendId.getCode().toString();
        if (popMap.containsKey(s)) {
            realtimePositioning.setSendId(Long.parseLong(popMap.get(s).toString()));
        }
        //接收方id
        s = PopMapEnum.ReceiveId.getCode().toString();
        if (popMap.containsKey(s)) {
            realtimePositioning.setReceiveId(Long.parseLong(popMap.get(s).toString()));
        }
        //定位状态
        s = PopMapEnum.LocationState.getCode().toString();
        if (popMap.containsKey(s)) {
            int i = Integer.parseInt(popMap.get(s).toString());
            LocationStateEnum locationStateEnum = LocationStateEnum.fromInt(i);
            if (locationStateEnum != null) {
                realtimePositioning.setLocationState(locationStateEnum.getText());
            }
        }
        //短报文类型
        s = PopMapEnum.ShortMsgType.getCode().toString();
        if (popMap.containsKey(s)) {
            int i = Integer.parseInt(popMap.get(s).toString());
            ShortMsgTypeEnum shortMsgTypeEnum = ShortMsgTypeEnum.fromInt(i);
            if (shortMsgTypeEnum != null) {
                realtimePositioning.setShortMsgType(shortMsgTypeEnum.getText());
            }
        }
        //短报文内容
        s = PopMapEnum.ShortMsg.getCode().toString();
        if (popMap.containsKey(s)) {
            realtimePositioning.setShortMsg(popMap.get(s).toString());
        }
        //传感器数组
        s = PopMapEnum.SensorList.getCode().toString();
        if (popMap.containsKey(s)) {
            realtimePositioning.setSensorList(JSON.parseArray(popMap.get(s).toString()));
        }
        //高程
        if (gps.getHgt() != null) {
            realtimePositioning.setHgt(Integer.parseInt(gps.getHgt().toString()));
        }
        return realtimePositioning;
    }

    @Override
    public List<JSONObjectPro> getMapDeviceList() {
        //查询车辆列表
        List<EquipmentInfo> equipmentList = equipmentManagementService.selectList(new EquipmentInfo()
                .setActivateStatus(ActivateStatusEnum.ACTIVATED.getCode()) //已激活设备
                .setNumberPlateNotEmpty(true));//设备名称不为空
        List<String> deviceIdList = equipmentList.stream().map(EquipmentInfo::getDeviceId).collect(Collectors.toList());
        //获取车辆最新状态
        Map<String, DeviceGps> cache = commonService.getDeviceOnlineDataFromCache(deviceIdList);
        //当前时间
        Date now = new Date();
        //返回结果
        List<JSONObjectPro> resultList = equipmentList.stream().filter(equipment -> {
            //过滤掉未定位的车辆
            DeviceGps device = cache.get(equipment.getDeviceId());
            return device != null && ComLbsUtils.getVehicleStatus(device).getCode() != VehicleStatusEnum.NOT_LOCATE.getCode();
        }).map(equipment -> {
            JSONObjectPro item = new JSONObjectPro()
                .put("equipmentId", equipment.getEquipmentId())
                .put("numberPlate", equipment.getNumberPlate())
                .put("deviceNo", equipment.getDeviceId())
                .put("objectId", equipment.getVehicleId())
                .put("companyId", equipment.getCompanyId().toString())
                .put("companyName", equipment.getCompanyName())
                .put("driverName", equipment.getDriverName())
                .put("channelsNum", equipment.getChannels())
                .put("objIcon", equipment.getObjIcon())
                .put("objType", equipment.getObjType())
                .put("objTypeName", ObjectTypeEnum.fromInt(equipment.getObjType()).getText())
                .put("type", OrgTypeEnum.DEVICE.getCode());
            //设置GPS数据
            DeviceGps device = cache.get(equipment.getDeviceId());
            if (ObjectUtils.isEmpty(device)){
                //前面过滤了此条件，但此判断先留着，以防后面又不过滤了
                item.put("lat", 0)
                    .put("lng", 0)
                    .put("gpsDateTime", "")
                    .put("vehicleStatus", VehicleStatusEnum.NOT_LOCATE.getText());
            }else {
                item.put("lat", device.getLat())
                    .put("lng", device.getLng())
                    .put("gpsDateTime", device.getGdt())
                    .put("spd", device.getSpd())
                    .put("dre", device.getDre())
                    .put("kilometer", device.getKilometer())
                    .put("dayKMeter", device.getDayKMeter())
                    .put("location", device.getLocation())
                    .put("satelliteCount", device.getSatelliteCount())
                    .put("hasAlarm", ObjectUtils.isNotEmpty(device.getAlm()));
                //设置状态
                VehicleStatusEnum vehicleStatus = ComLbsUtils.getVehicleStatus(device);
                item.put("vehicleStatus", vehicleStatus.getText());
                //根据状态设置备注信息
                //若设备在线，则显示具体速度或静止
                //若设备离线，则显示设备离线时长
                if (vehicleStatus == VehicleStatusEnum.DRIVING) {
                    item.put("remark", device.getSpd() + "km/h");
                } else if (vehicleStatus == VehicleStatusEnum.OFFLINE) {
                    item.put("remark", "离线" + DateUtils.timeDistance(now, DateUtils.parseDate(device.getGdt())));
                } else {
                    item.put("remark", vehicleStatus.getText());
                }
            }
            return item;
        }).sorted(Comparator.comparing((JSONObject x) -> x.getString("gpsDateTime")).reversed()).collect(Collectors.toList());
        return resultList;
    }

    /**
     * 获取设备实时视频通道号
     * @return
     */
    @Override
    public String[] realtimeDeviceVideoList(String deviceId){
        EquipmentManagement equipment = equipmentManagementService.getByDeviceId(deviceId);
        if (equipment == null) throw new ServiceException("无该设备！");
        String channelsNum = equipment.getChannelsNum();
        if (StringUtils.isEmpty(channelsNum)) throw new ServiceException("该设备无视频通道！");
        String[] channels = channelsNum.split(",");
        Arrays.sort(channels);
        return channels;
    }

    /**
     * 区域查车
     * @param param
     * @return
     */
    @Override
    public Object regionDeviceList(RegionDeviceParam param){
        if (DateUtils.parseDate(param.getStartTime()).after(DateUtils.parseDate(param.getEndTime()))){
            throw new ServiceException("开始时间不能大于结束时间！");
        }
        JSONObjectPro bigDataParam = new JSONObjectPro()
                .put("type", param.getType())
                .put("startTime", param.getStartTime())
                .put("endTime", param.getEndTime())
                .put("pointList", param.getPoints())
                .put("companyIdList", deptService.selectPermissionDeptId(param.getDeptId()).stream().map(Object::toString).collect(Collectors.toList()));
        if (param.getType() == RegionTypeEnum.CIRCLE.getCode()){
            bigDataParam.put("distance", param.getRadius()).put("circle", new Double[]{param.getCirclePoint().getLat(), param.getCirclePoint().getLng()});
        }
        BigDataResponse<List<Map<String, Object>>> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/gpsRelationData/queryPolygonDvoGeoInfo", bigDataParam, ArrayList.class);
        if (!response.isSuccess()) throw new BigDataException();
        response.getData().forEach(i -> {
            i.put("duration", DateUtils.timeDistance(DateUtils.parseDate(i.get("endTime").toString()), DateUtils.parseDate(i.get("startTime").toString())));
        });
        return response.getData();
    }

    /**
     * 设备数据导出
     * @return
     */
    @Override
    public List<MapDeviceExport> mapDeviceExport(MapDeviceExportParam param){
        //查询车辆列表
        List<VehicleManagement> vehicleList = vehicleManagementService.listMapVehicle(new VehicleManagement());
        //获取车辆最新状态
        Map<String, DeviceGps> cache = commonService.getDeviceOnlineDataFromCache();
        List<MapDeviceExport> resultList = vehicleList.stream().filter(vehicle -> param.getDeviceIds().contains(vehicle.getDeviceId())).map(i -> {
            DeviceGps device = cache.get(i.getDeviceId());
            MapDeviceExport export = new MapDeviceExport()
                    .setDvo(device.getDvo())
                    .setCompanyName(i.getCompanyName())
                    .setNumberPlate(i.getNumberPlate())
                    .setGdt(device.getGdt())
                    .setSpd(device.getSpd())
                    .setDayKMeter(device.getDayKMeter())
                    .setKilometer(device.getKilometer())
                    .setSatelliteCount(device.getSatelliteCount())
                    .setLocation(device.getLocation());
            return export;
        }).collect(Collectors.toList());
        return resultList;
    }

    /**
     * 获取报警数据列表
     * @param params
     * @return
     */
    @Override
    public List<AlarmData> alarmDataList(AlarmDataParam params){
        //获取报警类型集合
        Map<Integer, String> alarmTypeMap = alarmTypeService.selectList(new AlarmType()).stream().collect(Collectors.toMap(AlarmType::getType, AlarmType::getName, (var1, var2) -> var1));
        //组装大数据接口请求参数
        JSONObject paramMap = new JSONObject();
        if (com.ruoyi.common.utils.StringUtils.isNotEmpty(params.getDvo())){
            paramMap.put("dvo", Collections.singletonList(params.getDvo()));
        }
        if (params.getAlarmType() != null){
            paramMap.put("alarmTypes", Collections.singletonList(params.getAlarmType()));
        } else {
            paramMap.put("alarmTypes", alarmTypeMap.keySet());
        }
        if (com.ruoyi.common.utils.StringUtils.isNotEmpty(params.getStartTime())) {
            paramMap.put("startTime", params.getStartTime());
        }
        if (com.ruoyi.common.utils.StringUtils.isNotEmpty(params.getEndTime())) {
            paramMap.put("endTime", DateUtils.addSeconds(params.getEndTime(), 1));
        }
        BigDataResponse<List<Map<String, Object>>> response = HttpRequest.postJsonBigData(bigDataConfig.getApiUrl() + "/deviceAlarmData/queryList", paramMap,
                new TypeReference<List<Map<String, Object>>>(){}.getType());
        List<AlarmData> resultList = new ArrayList<>();
        if (response.isSuccess() && ObjectUtils.isNotEmpty(response.getData())){
            resultList = response.getData().stream().map(x -> {
                JSONObject item= JSONObject.from(x);
                AlarmData alarmData = new AlarmData()
                        .setNumberPlate(item.getString("numberPlate"))
                        .setAddress(item.getString("address"))
                        .setDeviceId(item.getString("dvo"))
                        .setLng(item.getDouble("lng"))
                        .setLat(item.getDouble("lat"))
                        .setSpd(item.getString("spd"))
                        .setAlarmType(item.getInteger("ate"))
                        .setAmc(item.getString("amc"));
                if (item.get("adt") != null) alarmData.setStartTime(new Date(item.getLong("adt")));
                if (com.ruoyi.common.utils.StringUtils.isEmpty(alarmTypeMap.get(alarmData.getAlarmType()))) alarmData.setAlarmTypeName("未知");
                else alarmData.setAlarmTypeName(alarmTypeMap.get(alarmData.getAlarmType()));
                return alarmData;
            }).collect(Collectors.toList());
        }
        return resultList;
    }
}
